package cn.org.alexander.execption;

import cn.org.alexander.entity.response.CommonCode;
import cn.org.alexander.entity.response.ResponseResult;
import cn.org.alexander.entity.response.ResultCode;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Alexander
 * @date 2022/5/21
 * @desc 全局异常
 */
@Slf4j
@RestControllerAdvice
public class ExceptionHandlerAdvice {

    private static ImmutableMap<Class<? extends Exception>, ResultCode> EXCEPTIONS;

    private static ImmutableMap.Builder<Class<? extends Exception>, ResultCode> builder = ImmutableMap.builder();


    static {
        //定义异常类型所对应的错误代码
        builder.put(HttpRequestMethodNotSupportedException.class, CommonCode.REQUEST_METHOD_ERROR);
        builder.put(NoHandlerFoundException.class, CommonCode.REQUEST_URL_NOT_MATCH);
        builder.put(MissingServletRequestParameterException.class, CommonCode.MISS_REQUEST_PARAM_ERROR);
        EXCEPTIONS = builder.build();
    }

    /**
     * 自定义异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({CustomException.class})
    public ResponseResult customExceptionHandler(CustomException ex) {
        if (ex.getStackTrace().length>2) {
            log.warn("业务异常信息:"+ex.getMessage()+"|出现位置:"+ex.getStackTrace()[1].toString()+"|"+ex.getStackTrace()[2].toString());
        }else {
            log.warn("业务异常信息:"+ex.getMessage()+"|出现位置:"+ex.getStackTrace()[1].toString());
        }
        if (Objects.isNull(ex.getResponseResult())) {
            ResultCode resultCode = ex.getResultCode();
            return new ResponseResult(resultCode);
        }
        return ex.getResponseResult();
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ResponseResult unKnowException(Exception ex) {
        log.error("occur param valid error!", ex);
        String message = "";
        if (ex instanceof MethodArgumentNotValidException) {
            List<ObjectError> allErrors = ((MethodArgumentNotValidException) ex).getBindingResult().getAllErrors();
            message = allErrors.stream().map(s -> s.getDefaultMessage()).collect(Collectors.joining(";"));
        }
        return ResponseResult.newErrorInstance(message);
    }

    @ExceptionHandler({Exception.class})
    public ResponseResult executionHandler(Exception ex) {
        //记录日志
        log.error(ex.getMessage(), ex);
        if (Objects.isNull(EXCEPTIONS)) {
            EXCEPTIONS = builder.build();
        }
        ResultCode resultCode = EXCEPTIONS.get(ex.getClass());
        if (!Objects.isNull(resultCode)) {
            return new ResponseResult(resultCode);
        }
        return ResponseResult.SERVER_ERROR();
    }
}
